home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / clchat413.lha / CLChat413 / ChatBot / source / chatbot.c < prev    next >
C/C++ Source or Header  |  1995-10-25  |  24KB  |  1,233 lines

  1. #include <proto/exec.h>
  2. #include <proto/dos.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <time.h>
  6. #include <dos/dostags.h>
  7. #include <dos/stdio.h>
  8.  
  9. #include <cl/lists.h>
  10. #include <cl/chatserver.h>
  11. #include "rev.h"
  12.  
  13. char version[]á= { "$VER: CLChat-ChatBot " VERTAG };
  14.  
  15. static int Done;
  16. static time_t starttime;
  17. static BPTR serverfh;
  18.  
  19. static char logoffmsg[á128 ] = {"Terminating..."};
  20.  
  21. static struct MsgPort *serverport, *myreplyport, *myport, *ipcport;
  22. static APTR myid;
  23.  
  24. static char fn_cmds[ 128 ], fn_patterns[á128 ], fn_dat[á128 ], fn_users[á128 ], fn_msg[á128 ];
  25.  
  26. struct myargs {
  27.     char *host;
  28.     ULONG *port;
  29.     char *nick;
  30.     char *realname;
  31.     char *channel;
  32.     char *cfgdir;
  33. } args;
  34.  
  35. static void initfn( void )
  36. {
  37.     strcpy( fn_cmds, args.cfgdir );
  38.     AddPart( fn_cmds, "ChatBot.Cmds", 128 );
  39.     strcpy( fn_patterns, args.cfgdir );
  40.     AddPart( fn_patterns, "ChatBot.Patterns", 128 );
  41.     strcpy( fn_dat, args.cfgdir );
  42.     AddPart( fn_dat, "ChatBot.Dat", 128 );
  43.     strcpy( fn_users, args.cfgdir );
  44.     AddPart( fn_users, "ChatBot.Users", 128 );
  45.     strcpy( fn_msg, args.cfgdir );
  46.     AddPart( fn_msg, "ChatBot.Msg", 128 );
  47. }
  48.  
  49. struct ipcmsg {
  50.     struct Message m;
  51.     char data[á256 ];
  52. };
  53.  
  54. struct nicksave {
  55.     char nick[á40 ];
  56.     char logoffmsg[á128 ];
  57.     ULONG count;
  58.     time_t lastlogoff;
  59.     char userhost[á128 ];
  60.     time_t created;            // When was this entry created
  61.     time_t onlineaccu;
  62.     time_t lastlogin;
  63.     ULONG valid;            // the above 3 entries are valid (0xAC1DAFFE)
  64.     ULONG accucount;
  65.     char reserved[á108 ];
  66. };
  67.  
  68. long __stack = 8192;
  69.  
  70. struct usernode {
  71.     struct MinNode n;
  72.     char username[á256 ];    // Already ParsedPattern
  73.     char nick[á32 ];    // Current nick
  74.     int pri;
  75.     ULONG autoop;
  76.     char comment[á256 ];
  77. };
  78.  
  79. struct nsn {
  80.     struct MinNode n;
  81.     char nick[á40 ];
  82. };
  83.  
  84. struct cmd {
  85.     struct MinNode n;
  86.     char cmd[á40 ];
  87.     int pri;
  88.     char exec[á256 ];
  89. };
  90.  
  91. struct pat {
  92.     struct MinNode n;
  93.     char pat[á256 ];
  94.     char exec[á256 ];
  95.     time_t lastused;
  96. };
  97.  
  98. struct MinList userlist;
  99. struct MinList nickscanlist;
  100. struct MinList cmdlist;
  101. struct MinList patlist;
  102.  
  103. static char *mynick;
  104.  
  105. static int shutup;
  106.  
  107. static UWORD fmtfunc[] = {á0x16c0, 0x4e75 };
  108. void __stdargs sprintf( char *to, char *fmt, ... )
  109. {
  110.     RawDoFmt( fmt, &fmt + 1, (APTR)fmtfunc, to );
  111. }
  112.  
  113. static void __stdargs sendmsg( char *fmt, ... )
  114. {
  115.     if( !serverfh )
  116.     {
  117.         struct chatmsg *svm;
  118.  
  119.         svm = malloc( sizeof( *svm ) );
  120.         svm->cmd = CM_DATA;
  121.         svm->id = myid;
  122.         svm->m.mn_ReplyPort = myreplyport;
  123.         
  124.         RawDoFmt( fmt, &fmt + 1, (APTR)fmtfunc, svm->data );
  125.         PutMsg( serverport, (struct Message*)svm );
  126.     }
  127.     else
  128.     {
  129.         VFPrintf( serverfh, fmt, &fmt + 1 );
  130.         FPutC( serverfh, '\n' );
  131.     }
  132. }
  133.  
  134. static int __stdargs expandtemplate( char *from, char *to, int maxlen, ... )
  135. {
  136.     ULONG *idp;
  137.     char **datap;
  138.     int ch;
  139.     char *oldto = to;
  140.  
  141.     while( *from )
  142.     {
  143.         if( *from != '%' )
  144.         {
  145.             *to++ = *from++;
  146.             continue;
  147.         }
  148.         from++;
  149.         ch         = *from++;
  150.         idp     = ( ULONG * ) &maxlen + 1;
  151.         datap     = ( char ** ) &idp[á1 ];
  152.         while( *idp )
  153.         {
  154.             /* Replacement char gefunden */
  155.             if( *idp == ch )
  156.             {
  157.                 if( *datap )
  158.                     strcpy( to, *datap );
  159.                 to = strchr( to, 0 );
  160.                 break;
  161.             }
  162.             idp++;
  163.             idp++;
  164.             datap++;
  165.             datap++;
  166.         }
  167.         /* Nicht gefunden, Zeichen 1:1 ⁿbernehmen */
  168.         if( !*idp )
  169.             *to++ = ch;
  170.     }
  171.     *to = 0;
  172.  
  173.     return( (int)strlen( oldto ) );
  174. }
  175.  
  176. static int findnick( char *nick, int remove )
  177. {
  178.     struct nsn *n;
  179.  
  180.     for( n = FIRSTNODE( &nickscanlist ); NEXTNODE( n ); n = NEXTNODE( n ) )
  181.     {
  182.         if( !stricmp( n->nick, nick ) )
  183.         {
  184.             if( remove )
  185.             {
  186.                 REMOVE( n );
  187.                 free( n );
  188.             }
  189.             return( 1 );
  190.         }
  191.     }
  192.     return( FALSE );
  193. }
  194.  
  195. static void addnicktoscanlist( char *nick )
  196. {
  197.     struct nsn *nsn;
  198.  
  199.     if( findnick( nick, FALSE ) )
  200.         return;
  201.     
  202.     nsn = malloc( sizeof( *nsn ) );
  203.     strcpy( nsn->nick, nick );
  204.     ADDTAIL( &nickscanlist, nsn );
  205. }
  206.  
  207. //
  208. //    Format der Userliste:
  209. //  Username Pri AutoopYN Comment
  210. //
  211.  
  212. static void clnl( char *s )
  213. {
  214.     s = stpbrk( s, "\r\n" );
  215.     if( s )
  216.         *s = 0;
  217. }
  218.  
  219. static void loadusers( void )
  220. {
  221.     BPTR f = Open( fn_users, MODE_OLDFILE );
  222.     char buffer[á512 ], *p;
  223.     struct usernode *un;
  224.  
  225.     NEWLIST( &userlist );
  226.  
  227.     if( !f )
  228.         return;
  229.  
  230.     while( FGets( f, buffer, 256 ) )
  231.     {
  232.         clnl( buffer );
  233.         if( buffer[á0 ]á== ';'á|| !buffer[á0 ]á|| buffer[á0 ]á== '#'á)
  234.             continue;
  235.  
  236.         un = malloc( sizeof( *un ) );
  237.         if( !un )
  238.             break;
  239.  
  240.         memset( un, 0, sizeof( *un ) );
  241.  
  242.         p = strtok( buffer, " \t"á);
  243.         if( !p )
  244.             continue;
  245.         ParsePatternNoCase( p, un->username, 256 );
  246.  
  247.         ADDTAIL( &userlist, un );
  248.  
  249.         p = strtok( NULL, " \t"á);
  250.         if( !p )
  251.             continue;
  252.         un->pri = atoi( p );
  253.  
  254.         p = strtok( NULL, " \t"á);
  255.         if( !p )
  256.             continue;
  257.         if( *p == 'Y' || *p == 'y'á)
  258.             un->autoop = TRUE;
  259.  
  260.         p = strtok( NULL, ""á);
  261.         if( !p )
  262.             continue;
  263.  
  264.         strcpy( un->comment, p );
  265.     }
  266.     Close( f );
  267. }
  268.  
  269. static void loadpatterns( void )
  270. {
  271.     BPTR f = Open( fn_patterns, MODE_OLDFILE );
  272.     char buffer[á512 ], *p;
  273.     struct pat *pn;
  274.  
  275.     NEWLIST( &patlist );
  276.  
  277.     if( !f )
  278.         return;
  279.  
  280.     while( FGets( f, buffer, 512 ) )
  281.     {
  282.         clnl( buffer );
  283.         if( buffer[á0 ]á== ';'á|| !buffer[á0 ]á)
  284.             continue;
  285.  
  286.         pn = malloc( sizeof( *pn ) );
  287.         if( !pn )
  288.             break;
  289.  
  290.         memset( pn, 0, sizeof( *pn ) );
  291.  
  292.         p = strtok( buffer, "  \t\""á);
  293.         if( !p )
  294.             continue;
  295.         ParsePatternNoCase( p, pn->pat, 256 );
  296.  
  297.         p = strtok( NULL, "╖"á);
  298.         if( !p )
  299.             continue;
  300.  
  301.         strcpy( pn->exec, p );
  302.         ADDTAIL( &patlist, pn );
  303.     }
  304.     Close( f );
  305. }
  306.  
  307.  
  308. static void loadcmd( void )
  309. {
  310.     BPTR f = Open( fn_cmds, MODE_OLDFILE );
  311.     char buffer[á256 ], *p;
  312.     struct cmd *un;
  313.  
  314.     NEWLIST( &cmdlist );
  315.  
  316.     if( !f )
  317.         return;
  318.  
  319.     while( FGets( f, buffer, 256 ) )
  320.     {
  321.         clnl( buffer );
  322.         if( buffer[á0 ]á== ';'á|| !buffer[á0 ]á|| buffer[á0 ]á== '#'á)
  323.             continue;
  324.  
  325.         un = malloc( sizeof( *un ) );
  326.         if( !un )
  327.             break;
  328.  
  329.         memset( un, 0, sizeof( *un ) );
  330.  
  331.         p = strtok( buffer, "  \t"á);
  332.         if( !p )
  333.             continue;
  334.         strcpy( un->cmd, p );
  335.  
  336.         p = strtok( NULL, "  \t"á);
  337.         if( !p )
  338.             continue;
  339.         un->pri = atoi( p );
  340.  
  341.         p = strchr( p, 0 ) + 1;
  342.         strcpy( un->exec, stpblk( p ) );
  343.  
  344.         ADDTAIL( &cmdlist, un );
  345.     }
  346.     Close( f );
  347. }
  348.  
  349. static struct cmd *findcmd( char *name )
  350. {
  351.     struct cmd *cmd;
  352.  
  353.     for( cmd = FIRSTNODE( &cmdlist ); NEXTNODE( cmd ); cmd = NEXTNODE( cmd ) )
  354.         if( !stricmp( cmd->cmd, name ) )
  355.             return( cmd );
  356.     return( NULL );
  357. }
  358.  
  359. static void chknicklogin( char *nick, char *userhost );
  360.  
  361. static void scanuser( char *nick, char *uid )
  362. {
  363.     struct usernode *un;
  364.     char *p2;
  365.     int rc;
  366.  
  367.     if( !uid || ( *uid != '[' && *uid != '(' )á)
  368.         return;
  369.  
  370.     uid++;
  371.  
  372.     p2 = strpbrk( uid, "\t  "á);
  373.     if( p2 )
  374.         *p2++ = 0;
  375.  
  376.     chknicklogin( nick, uid );
  377.  
  378.     // Ok, uid enthΣlt nun den usernamen zum nick
  379.     for( un = FIRSTNODE( &userlist ); NEXTNODE( un ); un = NEXTNODE( un ) )
  380.     {
  381.         if( MatchPatternNoCase( un->username, uid ) )
  382.         {
  383.             strcpy( un->nick, nick );
  384.  
  385.             if( rc = findnick( un->nick, TRUE ) )
  386.             {
  387.                 if( un->autoop )
  388.                     sendmsg( "/OP %s", nick );
  389.                 if( un->comment[á0 ]á)
  390.                     sendmsg( "%s", un->comment );
  391.             }
  392.             return;
  393.         }
  394.     }
  395. }
  396.  
  397. static int getuserpri( char *nick )
  398. {
  399.     struct usernode *un;
  400.  
  401.     for( un = FIRSTNODE( &userlist ); NEXTNODE( un ); un = NEXTNODE( un ) )
  402.     {
  403.         if( !stricmp( nick, un->nick ) )
  404.             return( un->pri );
  405.     }
  406.     return( 0 );
  407. }
  408.  
  409. static void killnick( char *nick )
  410. {
  411.     struct usernode *un;
  412.  
  413.     for( un = FIRSTNODE( &userlist ); NEXTNODE( un ); un = NEXTNODE( un ) )
  414.     {
  415.         if( !stricmp( nick, un->nick ) )
  416.         {
  417.             un->nick[á0 ]á= 0;
  418.             return;
  419.         }
  420.     }
  421. }
  422.  
  423. static void __stdargs answer( char *user, int priv, char *fmt, ... )
  424. {
  425.     char buffer[á512 ];
  426.  
  427.     if( user )
  428.     {
  429.         if( priv )
  430.         {
  431.             sprintf( buffer, "/QMSG %s ", user );
  432.         }
  433.         else
  434.         {
  435.             sprintf( buffer, "%s: ", user );
  436.         }
  437.     }
  438.     else
  439.         buffer[á0 ]á= 0;
  440.  
  441.     RawDoFmt( fmt, &fmt + 1, (APTR)fmtfunc, strchr( buffer, 0 ) );
  442.     sendmsg( "%s", buffer );
  443. }
  444.  
  445. static void exec( char *fromuser, int priv, char *exec, char *parms )
  446. {
  447.     char xb[á512 ];
  448.     BPTR ofh;
  449.  
  450.     if( parms && strpbrk( parms, "><" ) )
  451.         parms = NULL;
  452.  
  453.     expandtemplate( exec, xb, 512,
  454.         's', parms,
  455.         'S', parms,
  456.         'p', parms,
  457.         'P', parms,
  458.         'n', fromuser ? fromuser : "",
  459.         'N', fromuser ? fromuser : "",
  460.         NULL
  461.     );
  462.  
  463.     ofh = Open( "T:cbtmp", MODE_NEWFILE );
  464.  
  465.     SystemTags( xb,
  466.         SYS_Output, ofh,
  467.         TAG_DONE
  468.     );
  469.  
  470.     Seek( ofh, 0, OFFSET_BEGINNING );
  471.     Flush( ofh );
  472.  
  473.     while( FGets( ofh, xb, 255 ) )
  474.     {
  475.         clnl( xb );
  476.         answer( fromuser, priv, "%s", xb );
  477.         Delay( 25 );
  478.     }
  479.     Close( ofh );
  480.     //DeleteFile( "T:cbtmp" );
  481. }
  482.  
  483. static int findnicklogin( char *nick, struct nicksave *to, BPTR f )
  484. {
  485.     while( FRead( f, to, sizeof( *to ), 1 ) == 1 )
  486.     {
  487.         if( !stricmp( to->nick, nick ) )
  488.             return( TRUE );
  489.     }
  490.     return( FALSE );
  491. }
  492.  
  493. static int findnicksave( char *nick, struct nicksave *to )
  494. {
  495.     BPTR f = Open( fn_dat, MODE_READWRITE );
  496.     struct nicksave ns;
  497.  
  498.     if( !f )
  499.         return( FALSE );
  500.  
  501.     SetVBuf( f, 0, BUF_FULL, 32 * sizeof( ns ) );
  502.  
  503.     if( findnicklogin( nick, to, f ) )
  504.     {
  505.         Close( f );
  506.         return( TRUE );
  507.     }
  508.     Close( f );
  509.     return( FALSE );
  510. }
  511.  
  512. static void handlecmd( char *fromuser, int priv, char *cmd )
  513. {
  514.     char *p = stpbrk( cmd, "  \t," );
  515.     struct cmd *cmn;
  516.     int pri = getuserpri( fromuser );
  517.  
  518.     if( !stricmp( fromuser, mynick ) )
  519.         return;
  520.  
  521.     if( p )
  522.     {
  523.         *p++ = 0;
  524.         p = stpblk( p );
  525.     }
  526.     else
  527.         p = "";
  528.  
  529.     if( !stricmp( cmd, "STATUS" ) )
  530.     {
  531.         char x[á6 ];
  532.         struct nicksave ns;
  533.  
  534.         if( *p && pri >= 99 )
  535.         {
  536.             if( !findnicksave( p, &ns ) )
  537.             {
  538.                 answer( fromuser, priv, "Sorry, no status for %s available.\n", p );
  539.                 return;
  540.             }
  541.             utunpk( ns.created, x );
  542.  
  543.             answer( fromuser, priv, "%s has logged in %ld times. I've first seen that user on %02ld-%02ld-%04ld. Since then, he has been online for %ld days, %ld hours and %ld mins. His average online time per login is ~%ld minutes, counting %ld logins i've tracked.", 
  544.                 p,
  545.                 ns.count,
  546.                 x[ 2 ], x[ 1 ], x[á0 ]á+ 1970,
  547.                 ns.onlineaccu / ( 24 * 3600 ),
  548.                 ( ns.onlineaccu / 3600 ) % 24,
  549.                 ( ns.onlineaccu / 60 ) % 60,
  550.                 ns.accucount ? ( ( ( ns.onlineaccu / ns.accucount ) + 59 ) / 60 ) : 0,
  551.                 ns.accucount
  552.             );
  553.             return;
  554.         }
  555.  
  556.         if( !findnicksave( fromuser, &ns ) || ns.count < 2 )
  557.         {
  558.             answer( fromuser, priv, "Your status is %ld. This is the first time that i have seen you.", pri, ns.count );
  559.         }
  560.         else
  561.         {
  562.             utunpk( ns.created, x );
  563.  
  564.             answer( fromuser, priv, "Your status is %ld. You've logged in %ld times. I've first seen you on %02ld-%02ld-%04ld. Since then, you have been online for %ld days, %ld hours and %ld mins. Your average online time per login is ~%ld minutes, counting %ld logins i've tracked.", 
  565.                 pri, 
  566.                 ns.count,
  567.                 x[ 2 ], x[ 1 ], x[á0 ]á+ 1970,
  568.                 ns.onlineaccu / ( 24 * 3600 ),
  569.                 ( ns.onlineaccu / 3600 ) % 24,
  570.                 ( ns.onlineaccu / 60 ) % 60,
  571.                 ns.accucount ? ( ( ( ns.onlineaccu / ns.accucount ) + 59 ) / 60 ) : 0,
  572.                 ns.accucount
  573.             );
  574.         }
  575.         return;
  576.     }
  577.     else if( !stricmp( cmd, "VERSION" ) || !stricmp( cmd, "*!VER" ) )
  578.     {
  579.         answer( fromuser, priv, "VERSION CLChat-ChatBot/AmigaOS " VERTAG, pri );
  580.         return;
  581.     }
  582.     else if( !stricmp( cmd, "UPTIME" ) )
  583.     {
  584.         time_t t = time( NULL ) - starttime;
  585.         int numuser = 0;
  586.         BPTR f = Lock( fn_dat, SHARED_LOCK );
  587.         if( f )
  588.         {
  589.             __aligned struct FileInfoBlock fib;
  590.             Examine( f, &fib );
  591.             UnLock( f );
  592.             numuser = fib.fib_Size / sizeof( struct nicksave );
  593.         }
  594.  
  595.         answer( fromuser, priv, "I'm up for %ldd, %ldh, %ldm, %lds. I know of %ld users.",
  596.             t / ( 3600 * 24 ),
  597.             ( t / 3600 ) % 24,
  598.             ( t / 60 ) % 60,
  599.             ( t ) % 60,
  600.             numuser
  601.         );
  602.     }
  603.     else if( !stricmp( cmd, "UNKNOWN" ) )
  604.     {
  605.         return;    // Silent ignore...
  606.     }
  607.     else if( !stricmp( cmd, "SHUTUP" ) )
  608.     {
  609.         answer( fromuser, priv, "Ok, I'm quiet now." );
  610.         shutup = TRUE;
  611.     }
  612.     else if( !stricmp( cmd, "TALK" ) )
  613.     {
  614.         answer( fromuser, priv, "Ok, I'm talking again." );
  615.         shutup = FALSE;
  616.     }
  617.     else if( !stricmp( cmd, "MSG" ) )
  618.     {
  619.         char *p2 = stpbrk( p ? p : "", "\t  " );
  620.  
  621.         if( !p || !*p || !p2 )
  622.         {
  623.             answer( fromuser, priv, "Usage: MSG nick msgtext" );
  624.         }
  625.         else
  626.         {
  627.             char msgfn[á256 ];
  628.             BPTR f;
  629.  
  630.             *p2++ = 0;
  631.             p2 = stpblk( p2 );
  632.  
  633.             if( stpbrk( p, ":/ \t@" ) )
  634.             {
  635.                 answer( fromuser, priv, "Invalid nick \"%s\" specified.", p );
  636.                 return;
  637.             }
  638.  
  639.             strcpy( msgfn, fn_msg );
  640.             strcat( msgfn, p );
  641.             f = Open( msgfn, MODE_READWRITE );
  642.             if( !f )
  643.             {
  644.                 answer( fromuser, priv, "Can't store MSG for %s.", p );
  645.                 return;
  646.             }
  647.  
  648.             Seek( f, 0, OFFSET_END );
  649.             utunpk( time( NULL ), msgfn );
  650.             FPrintf( f, "** I've got a message for you from %s, stored %02ld:%02ld:%02ld on %02ld-%02ld-%02ld:\n",
  651.                 fromuser,
  652.                 msgfn[ 3 ], msgfn[ 4 ], msgfn[ 5 ],
  653.                 msgfn[ 2 ], msgfn[ 1 ], msgfn[á0 ]á+ 70
  654.             );
  655.             FPrintf( f, "** %s\n", p2 );
  656.             Close( f );
  657.             answer( fromuser, priv, "MSG for %s stored.", p );
  658.         }
  659.     }
  660.     else if( !stricmp( cmd, "SEEN" ) )
  661.     {
  662.         struct nicksave ns;
  663.  
  664.         if( !*p )
  665.         {
  666.             answer( fromuser, priv, "Usage: SEEN <nick>" );
  667.             return;
  668.         }
  669.  
  670.         if( !stricmp( p, mynick ) )
  671.         {
  672.             answer( fromuser, priv, "I don't have a mirror at hand and therefore can't see me. I'm here, anyway. Believe me!" );
  673.             return;
  674.         }
  675.         if( !stricmp( p, fromuser ) )
  676.         {
  677.             answer( fromuser, priv, "Hm, sorry, i can't see you right now. Perhaps you'll come back later. Better ask yourself." );
  678.             return;
  679.         }
  680.  
  681.         if( findnicksave( p, &ns ) )
  682.         {
  683.             if( !ns.lastlogoff )
  684.                 answer( fromuser, priv, "%s (%s) is currently online.", p, ns.userhost );
  685.             else if( ns.lastlogoff == ~0 )
  686.                 answer( fromuser, priv, "Sorry, I've missed %s's (%s) last logoff.", p, ns.userhost );
  687.             else
  688.             {
  689.                 time_t age = time( NULL ) - ns.lastlogoff;
  690.                 if( age > ( 24 * 3600 ) )
  691.                 {
  692.                     answer( fromuser, priv, "I haven't seen %s (%s) for %ld days.", p, ns.userhost, age / ( 24 * 3600 ) );
  693.                 }
  694.                 else if( age > 3600 )
  695.                 {
  696.                     answer( fromuser, priv, "%s (%s) logged out %ld hour(s) ago (%s).", p, ns.userhost, age / 3600, ns.logoffmsg );
  697.                 }
  698.                 else
  699.                 {
  700.                     answer( fromuser, priv, "%s (%s) logged out %ld minute(s) ago (%s).", p, ns.userhost, ( age + 59 ) / 60, ns.logoffmsg );
  701.                 }
  702.             }
  703.         }
  704.         else
  705.             answer( fromuser, priv, "I've never seen %s!", p );
  706.     }
  707.     else if( !stricmp( cmd, "QUIT" ) && pri > 90 )
  708.     {
  709.         if( p && *p )
  710.             strcpy( logoffmsg, p );
  711.         Done = TRUE;
  712.         return;
  713.     }
  714.     else if( !stricmp( cmd, "RELOAD" ) && pri > 90 )
  715.     {
  716.         NEWLIST( &nickscanlist );
  717.         sendmsg( "/USERS" );
  718.         loadusers();
  719.         loadcmd();
  720.         loadpatterns();
  721.         answer( fromuser, priv, "Reload of configuration complete!" );
  722.         return;
  723.     }
  724.     else if( !stricmp( cmd, "EMIT" ) && pri >= 99 )
  725.     {
  726.         sendmsg( "%s", p );
  727.         return;
  728.     }
  729.     else if( !strnicmp( cmd, "*!PING", 6 ) && priv )
  730.     {
  731.         sendmsg( "/QMSG %s *!PONG%s", fromuser, &cmd[á6 ]á);
  732.         return;
  733.     }
  734.     else if( !strnicmp( cmd, "*!-CLFTREQ", 10 ) && priv )
  735.     {
  736.         sendmsg( "/QMSG %s You can't send files to me!", fromuser );
  737.         return;
  738.     }
  739.     else if( !strnicmp( cmd, "\001DCC", 4 ) && priv )
  740.     {
  741.         sendmsg( "/QMSG %s I can't accept DCC requests!", fromuser );
  742.         return;
  743.     }
  744.     else if( !stricmp( cmd, "?" ) || !stricmp( cmd, "HELP" ) )
  745.     {
  746.         char replybuffer[á512 ];
  747.  
  748.         strcpy( replybuffer, "Status, Version, Uptime, Seen, MSG" );
  749.         if( pri > 90 )
  750.             strcat( replybuffer, ", Quit, Reload, Shutup, Talk" );
  751.         if( pri >= 99 )
  752.             strcat( replybuffer, ", Emit" );
  753.  
  754.         answer( fromuser, priv, "Commands available for status %ld:", pri );
  755.  
  756.         for( cmn = FIRSTNODE( &cmdlist ); NEXTNODE( cmn ); cmn = NEXTNODE( cmn ) )
  757.         {
  758.             if( cmn->pri > pri )
  759.                 continue;
  760.             if( replybuffer[á0 ]á)
  761.                 strcat( replybuffer, ", " );
  762.             strcat( replybuffer, cmn->cmd );
  763.             if( strlen( replybuffer ) > 256 )
  764.             {
  765.                 answer( fromuser, priv, replybuffer );
  766.                 replybuffer[á0 ]á= 0;
  767.             }
  768.         }
  769.         if( replybuffer[á0 ]á)
  770.             answer( fromuser, priv, replybuffer );
  771.     }
  772.     else
  773.     {
  774.         cmn = findcmd( cmd );
  775.         if( !cmn || cmn->pri > pri )
  776.         {
  777.             if( stricmp( fromuser, cmd ) )
  778.             {
  779.                 answer( fromuser, priv, "Unknown command \"%s\". Try \"/MSG %s HELP\" for a list of commands.",
  780.                     cmd, mynick
  781.                 );
  782.             }
  783.             return;
  784.  
  785.         }
  786.  
  787.         // Kommando ausfⁿhren
  788.         exec( fromuser, priv, cmn->exec, p );
  789.     }
  790. }
  791.  
  792. static void findpat( char *pat )
  793. {
  794.     struct pat *pn;
  795.  
  796.     if( shutup )
  797.         return;
  798.  
  799.     for( pn = FIRSTNODE( &patlist ); NEXTNODE( pn ); pn = NEXTNODE( pn ) )
  800.     {
  801.         if( MatchPatternNoCase( pn->pat, pat ) )
  802.         {
  803.             time_t t;
  804.  
  805.             time( &t );
  806.  
  807.             if( t - pn->lastused > 10 )
  808.             {
  809.                 exec( NULL, 0, pn->exec, pat );
  810.                 pn->lastused = time( NULL );
  811.             }
  812.             break;
  813.         }
  814.     }
  815. }
  816.  
  817. static void initnicksave( void )
  818. {
  819.     BPTR f = Open( fn_dat, MODE_READWRITE );
  820.     struct nicksave ns;
  821.  
  822.     SetVBuf( f, 0, BUF_FULL, 32 * sizeof( ns ) );
  823.  
  824.     while( FRead( f, &ns, sizeof( ns ), 1 ) == 1 )
  825.     {
  826.         if( !ns.lastlogoff )
  827.         {
  828.             ns.lastlogoff = ~0;
  829.             Seek( f, -sizeof( ns ), OFFSET_CURRENT );
  830.             FWrite( f, &ns, sizeof( ns ), 1 );
  831.         }
  832.     }
  833.     Close( f );
  834. }
  835.  
  836. static void chknicklogin( char *nick, char *userhost )
  837. {
  838.     BPTR f = Open( fn_dat, MODE_READWRITE );
  839.     struct nicksave ns;
  840.  
  841.     if( !f )
  842.         return;
  843.  
  844.     SetVBuf( f, 0, BUF_FULL, 32 * sizeof( ns ) );
  845.  
  846.     if( findnicklogin( nick, &ns, f ) )    
  847.     {
  848.         Seek( f, -sizeof( ns ), OFFSET_CURRENT );
  849.     }
  850.     else
  851.     {
  852.         memset( &ns, 0, sizeof( ns ) );
  853.         strcpy( ns.nick, nick );
  854.     }
  855.     if( ns.valid != 0xAC1DAFFE )
  856.     {
  857.         ns.valid = 0xAC1DAFFE;
  858.         ns.onlineaccu = 0;
  859.         ns.accucount = 0;
  860.         time( &ns.created );
  861.     }
  862.  
  863.     time( &ns.lastlogin );
  864.     ns.count++;
  865.     ns.lastlogoff = NULL;
  866.     strncpy( ns.userhost, userhost, 127 );
  867.     ns.userhost[á127 ]á= 0;
  868.     FWrite( f, &ns, sizeof( ns ), 1 );
  869.     Close( f );
  870. }
  871.  
  872. static void chknicklogoff( char *nick, char *msg )
  873. {
  874.     BPTR f = Open( fn_dat, MODE_READWRITE );
  875.     struct nicksave ns;
  876.  
  877.     if( !f )
  878.         return;
  879.  
  880.     SetVBuf( f, 0, BUF_FULL, 32 * sizeof( ns ) );
  881.  
  882.     if( findnicklogin( nick, &ns, f ) )    
  883.     {
  884.         Seek( f, -sizeof( ns ), OFFSET_CURRENT );
  885.         time( &ns.lastlogoff );
  886.         strncpy( ns.logoffmsg, msg, 127 );
  887.         ns.logoffmsg[á127 ]á= 0;
  888.  
  889.         if( ( ns.lastlogoff - ns.lastlogin > 120 ) )
  890.         {
  891.             ns.onlineaccu += ns.lastlogoff - ns.lastlogin;
  892.             ns.accucount++;
  893.         }
  894.         FWrite( f, &ns, sizeof( ns ), 1 );
  895.     }
  896.     Close( f );
  897. }
  898.  
  899. static void chkmsgs( char *nick )
  900. {
  901.     char msgfn[á256 ];
  902.     char buffer[á256 ];
  903.     BPTR f;
  904.  
  905.     strcpy( msgfn, fn_msg );
  906.     strcat( msgfn, nick );
  907.     f = Open( msgfn, MODE_OLDFILE );
  908.     if( !f )
  909.         return;
  910.  
  911.     while( FGets( f, buffer, 256 ) )
  912.     {
  913.         clnl( buffer );
  914.         sendmsg( "/QMSG %s %s", nick, buffer );
  915.     }
  916.     Close( f );
  917.     DeleteFile( msgfn );
  918. }
  919.  
  920. void __stdargs __main( char *thissiimplysucks )
  921. {
  922.     char buffer[á512 ], oldbuffer[á512 ], *p, *p2, *p3;
  923.     char hostname[á64 ], ipcportname[á128 ];
  924.     static struct chatmsg *loginmsg;
  925.     int c;
  926.     struct RDArgs *rda;
  927.     ULONG dummy = 5555;
  928.  
  929.     Printf( "%s\n(C) 1995 Oliver Wagner (o.wagner@lsd.wupper.de), All Rights Reserved\n", &version[á6 ]á);
  930.  
  931.     NEWLIST( &nickscanlist );
  932.  
  933.     args.port = &dummy;
  934.     args.cfgdir = "S:";
  935.     if( !( rda = ReadArgs( "Host/K,Port/K/N,Nick/A,Realname/A,Channel=AutoJoin/K,Dir=CFGDir/K", &args, NULL ) ) )
  936.     {
  937.         PrintFault( IoErr(), "ChatBot" );
  938.         exit( 20 );
  939.     }
  940.  
  941.     initfn();
  942.  
  943.     if( args.host )
  944.     {
  945.         sprintf( hostname, "TCP:%s/%ld", args.host, *args.portá);
  946.         Printf( "Attempting connect to %s...\n", hostname );
  947.         serverfh = Open( hostname, MODE_NEWFILE );
  948.         if( !serverfh )
  949.         {
  950.             Printf( "ChatBot: unable to connect to %s, err %ld\n", hostname, IoErr() );
  951.             exit( 10 );
  952.         }
  953.         //SetVBuf( serverfh, 0, BUF_NONE, 512 );
  954.     }
  955.  
  956.     GetVar( "HOSTNAME", hostname, 64, 0 );
  957.  
  958.     if( !serverfh )
  959.     {
  960.         for( c = 0; c < 30; c++ )
  961.         {
  962.             serverport = FindPort( CPNAME );
  963.             if( serverport )
  964.                 break;
  965.             Delay( 50 );
  966.         }
  967.         if( !serverport )
  968.         {
  969.             PutStr( "Unable to find Chat Server.\n" );
  970.             FreeArgs( rda );
  971.             exit( 20 );
  972.         }
  973.  
  974.         myreplyport = CreateMsgPort();
  975.         myport = CreateMsgPort();
  976.  
  977.         loginmsg = malloc( sizeof( *loginmsg ) );
  978.         sprintf( loginmsg->data, "%s %s@%s %s", mynick = args.nick, mynick, hostname, args.realname );
  979.         loginmsg->id = myport;
  980.         loginmsg->cmd = CM_LOGIN;
  981.         loginmsg->m.mn_ReplyPort = myreplyport;
  982.         PutMsg( serverport,  (struct Message*)loginmsg );
  983.         WaitPort( myreplyport );
  984.         GetMsg( myreplyport );
  985.         if( loginmsg->cmd )
  986.         {
  987.             Printf( "Chat login failed: %ld\n", loginmsg->cmd );
  988.             DeleteMsgPort( myreplyport );
  989.             DeleteMsgPort( myport );
  990.             FreeArgs( rda );
  991.             exit( 10 );
  992.         }
  993.         myid = loginmsg->id;
  994.         free( loginmsg );
  995.     }
  996.     else
  997.     {
  998.         mynick = args.nick;
  999.         FPrintf( serverfh, "%s %s@%s %s\n", mynick, mynick, hostname, args.realnameá);
  1000.     }
  1001.  
  1002.     loadusers();
  1003.     loadcmd();
  1004.     loadpatterns();
  1005.     initnicksave();
  1006.  
  1007.     time( &starttime );
  1008.  
  1009.     if( args.channel )
  1010.         sendmsg( "/JOIN %s", args.channelá);
  1011.  
  1012.     sprintf( ipcportname, "CHATBOT_%s", mynická);
  1013.     strupr( ipcportname );
  1014.  
  1015.     ipcport = CreatePort( ipcportname, -32 );
  1016.  
  1017.     while( !Done )
  1018.     {
  1019.         struct ipcmsg *ipcmsg;
  1020.  
  1021.         if( !serverfh )
  1022.         {
  1023.             while( loginmsg = (struct chatmsg*)GetMsg( myreplyport ) )
  1024.                 free( loginmsg );
  1025.         }
  1026.  
  1027.         while( ipcmsg = GetMsg( ipcport ) ) 
  1028.         {
  1029.             sendmsg( "%s", ipcmsg->data );
  1030.             ReplyMsg( ipcmsg );
  1031.         }
  1032.  
  1033.         if( CheckSignal( SIGBREAKF_CTRL_C ) )
  1034.             break;
  1035.  
  1036.         if( !serverfh )
  1037.         {
  1038.             if( !( loginmsg = (struct chatmsg*)GetMsg( myport ) ) )
  1039.             {
  1040.                 Wait( ( 1L<<myport->mp_SigBit ) | ( 1L << ipcport->mp_SigBit ) | ( 1L << myreplyport->mp_SigBit ) );
  1041.                 continue;
  1042.             }
  1043.  
  1044.             if( loginmsg->cmd != CM_DATA )
  1045.             {
  1046.                 ReplyMsg( loginmsg );
  1047.                 break;
  1048.             }
  1049.             strcpy( buffer, loginmsg->data );
  1050.             ReplyMsg( loginmsg );
  1051.         }
  1052.         else
  1053.         {
  1054.             if( !WaitForChar( serverfh, 100000 ) )
  1055.                 continue;
  1056.  
  1057.             if( !FGets( serverfh, buffer, 511 ) )
  1058.                 break;
  1059.             clnl( buffer );
  1060.         }
  1061.  
  1062.         Printf( "%s\n", buffer );
  1063.         //clnl( buffer );
  1064.         if( !buffer[á0 ]á)
  1065.             continue;    // Tick
  1066.  
  1067.         // Parsen
  1068.         if( buffer[á0 ]á== '[' )
  1069.         {
  1070.             p = strchr( buffer, ']' );
  1071.             if( !p )
  1072.                 continue;
  1073.             *p++ = 0;
  1074.             p = stpblk( p );
  1075.             p2 = stpbrk( p, "\t " );
  1076.             if( p2 )
  1077.             {
  1078.                 *p2++ = 0;
  1079.                 p3 = stpbrk( p2, "\t " );
  1080.                 if( p3 )
  1081.                     *p3++ = 0;
  1082.             }
  1083.  
  1084.             // Server-Cmd in Buffer
  1085.             if( !stricmp( &buffer[á1 ], "USERS" ) )
  1086.             {
  1087.                 // WHOIS schicken, um Userliste upzudaten
  1088.                 if( *p == '!' || *p == '@'á|| *p == '>'á)
  1089.                 {
  1090.                     if( !findnick( p + 1, FALSE ) )
  1091.                     {
  1092.                         addnicktoscanlist( p + 1 );
  1093.                         sendmsg( "/WHOIS %s", p + 1 );
  1094.                     }
  1095.                     continue;
  1096.                 }
  1097.             }
  1098.             else if( !stricmp( &buffer[á1 ], "WHOIS" ) )
  1099.             {
  1100.                 if( !stricmp( p, "Nick" ) )
  1101.                 {
  1102.                     scanuser( p2, p3 );
  1103.                 }                
  1104.             }
  1105.             else if( !stricmp( &buffer[á1 ], "JOIN" ) )
  1106.             {
  1107.                 if( stricmp( mynick, p ) )
  1108.                 {
  1109.                     addnicktoscanlist( p );
  1110.                     sendmsg( "/WHOIS %s", p );
  1111.                 }
  1112.             }
  1113.             else if( !stricmp( &buffer[á1 ], "ENTER" ) )
  1114.             {
  1115.                 if( stricmp( mynick, p ) )
  1116.                 {
  1117.                     char *p4 = strrchr( p2, ')' );
  1118.                     *p4 = 0;
  1119.                     addnicktoscanlist( p );
  1120.                     scanuser( p, p2 );
  1121.                     chkmsgs( p );
  1122.                 }
  1123.             }
  1124.             else if( !stricmp( &buffer[á1 ], "EXIT" ) )
  1125.             {
  1126.                 char *p4 = strchr( p3, '(' );
  1127.                 if( p4 )
  1128.                 {
  1129.                     char *p5;
  1130.  
  1131.                     p4++;
  1132.                     p5 = strrchr( p4, ')'á);
  1133.                     if( p5 )
  1134.                         *p5 = 0;
  1135.                 }
  1136.                 killnick( p );
  1137.                 chknicklogoff( p, p4 ? p4 : "none" );
  1138.             }
  1139.             else if( !stricmp( &buffer[á1 ], "NICK" ) )
  1140.             {
  1141.                 char bf[á128 ];
  1142.  
  1143.                 p3 = strrchr( p3, ' 'á);
  1144.                 if( !p3 )
  1145.                     continue;
  1146.                 *p3++ = 0;
  1147.                 p2 = strchr( p3, '.'á);
  1148.                 if( p2 )
  1149.                     *p2 = 0;
  1150.  
  1151.                 sprintf( bf, "renamed to %s", p3 );
  1152.                 chknicklogoff( p, bf );
  1153.  
  1154.                 sendmsg( "/WHOIS %s", p3 );
  1155.             }
  1156.         }
  1157.         else if( buffer[á0 ]á== '<'á)    // Priv
  1158.         {
  1159.             p = strchr( buffer, '>' );
  1160.             if( !p )
  1161.                 continue;
  1162.             *p++ = 0;
  1163.             handlecmd( &buffer[á1 ], TRUE, stpblk( p ) );
  1164.         }
  1165.         else if( buffer[á0 ]á== 2 )
  1166.         {
  1167.             static char nickbf[á40 ];
  1168.             strncpy( nickbf, &buffer[ 1 ], 39 );
  1169.             mynick = nickbf;
  1170.             p = stpbrk( mynick, " \t " );
  1171.             if( p )
  1172.                 *p = 0;
  1173.         }
  1174.         else // ╓ffentlich, 
  1175.         {
  1176.             p = strchr( buffer, ':' );
  1177.             if( !p )
  1178.                 continue;
  1179.             strcpy( oldbuffer, buffer );
  1180.             *p++ = 0;
  1181.             p = stpblk( p );
  1182.  
  1183.             if( !stricmp( p, "PING" ) )
  1184.             {
  1185.                 sendmsg( "\002*PONG*" );
  1186.                 continue;
  1187.             }
  1188.  
  1189.             p2 = stpbrk( p, "\t:,  " );
  1190.             if( !p2 )
  1191.             {
  1192.                 if( stricmp( buffer, mynick ) )
  1193.                     findpat( oldbuffer );
  1194.                 continue;
  1195.             }
  1196.             *p2++ = 0;
  1197.  
  1198.             if( stricmp( p, mynick ) )
  1199.             {
  1200.                 if( stricmp( buffer, mynick ) )
  1201.                     findpat( oldbuffer );
  1202.                 continue;
  1203.             }
  1204.  
  1205.             handlecmd( buffer, FALSE, stpblk( p2 ) );
  1206.         }
  1207.     }
  1208.  
  1209.     if( !serverfh )
  1210.     {
  1211.         loginmsg = malloc( sizeof( *loginmsg ) );
  1212.         loginmsg->id = myid;
  1213.         loginmsg->cmd = CM_LOGOFF;
  1214.         loginmsg->m.mn_ReplyPort = myreplyport;
  1215.         strcpy( loginmsg->data, logoffmsg );
  1216.         PutMsg( serverport,  (struct Message*)loginmsg ); 
  1217.         Delay( 50 );
  1218.         while( loginmsg = (struct chatmsg*)GetMsg( myport ) ) 
  1219.             ReplyMsg( loginmsg );
  1220.     }
  1221.     else
  1222.     {
  1223.         FPrintf( serverfh, "/QUIT Terminating...\n" );
  1224.         Close( serverfh );
  1225.     }
  1226.  
  1227.     DeleteMsgPort( myreplyport );
  1228.     DeleteMsgPort( myport );
  1229.     DeletePort( ipcport );
  1230.     FreeArgs( rda );
  1231.     exit( 0 );
  1232. }
  1233.